package org.linlinjava.litemall.admin.service;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.linlinjava.litemall.admin.beans.dto.AdminRewardConfigDto;
import org.linlinjava.litemall.admin.beans.dto.AdminRewardDto;
import org.linlinjava.litemall.admin.beans.vo.*;
import org.linlinjava.litemall.admin.dto.DistributionLogAndDetailDTO;
import org.linlinjava.litemall.admin.util.PageUtil;
import org.linlinjava.litemall.admin.vo.DistributionLogAndDetailVO;
import org.linlinjava.litemall.admin.vo.PeriodStatisticsVO;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.db.dao.LitemallCouponMapper;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.service.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 管理奖励服务
 *
 * @author yliyun
 * @program: litemall
 * @description: reward
 * @author: chenyu
 * @create: 2022-03-15 11:13
 * @date 2022/09/14
 */
@Service
public class AdminRewardService {
    /**
     * litemall奖励规则服务
     */
    @Autowired
    private LitemallRewardRuleService litemallRewardRuleService;

    /**
     * litemall奖励规则配置服务
     */
    @Autowired
    private LitemallRewardRuleConfigService litemallRewardRuleConfigService;

    /**
     * litemall分配日志服务
     */
    @Autowired
    private LitemallDistributionLogService litemallDistributionLogService;

    /**
     * litemall分布细节服务
     */
    @Autowired
    private LitemallDistributionDetailService litemallDistributionDetailService;

    /**
     * 用户服务
     */
    @Autowired
    private LitemallUserService userService;

    @Autowired
    private LumiereCouponStrategyService lumiereCouponStrategyService;
    @Autowired
    private LumiereCouponService lumiereCouponService;

    /**
     * 息服务
     */
    @Autowired
    private LumiereCouponService couponService;

    @Resource
    private LitemallCouponMapper couponMapper;

    /**
     * 管理服务
     */
    @Autowired
    private LitemallAdminService adminService;

    /**
     * 分配日志服务
     */
    @Autowired
    private DistributionLogService distributionLogService;


    /**
     * 规则列表
     *
     * @param isExpired 是过期
     * @param page      页面
     * @param limit     限制
     * @param sort      排序
     * @param order     订单
     * @param ruleName  规则名称
     * @param status    状态
     * @return {@link Object}
     */
    public Object listRule(Byte isExpired, Integer page,
                           Integer limit, String sort, String order, String ruleName, Byte status) {
        List<LitemallRewardRule> list = litemallRewardRuleService.list(ruleName, status,null,false);

        List<AdminRewardRuleVo> vos = new ArrayList<>();
        List<AdminRewardRuleVo> finalVos = vos;
        if (isExpired != null) {
            list = list.stream().sorted(Comparator.comparing(LitemallRewardRule::getStatus)).collect(Collectors.toList());

            vos = list.stream().map(rule -> {
                AdminRewardRuleVo vo = new AdminRewardRuleVo();
                BeanUtils.copyProperties(rule, vo);
                if (rule.getAddAdminId() != null) {
                    LitemallAdmin adminUser = adminService.findById(rule.getAddAdminId());
                    if (adminUser != null) {
                        vo.setAddAdminName(adminUser.getUsername());
                    }
                }
                return vo;
            }).collect(Collectors.toList());
        } else {
            list = list.stream().sorted(Comparator.comparing(
                    LitemallRewardRule::getStatus).reversed()).collect(Collectors.toList());

            list.stream().forEach(rule -> {
                AdminRewardRuleVo vo = new AdminRewardRuleVo();
                if (rule.getEndDate() != null) {
                    if (rule.getEndDate().isAfter(LocalDate.now())) {
                        vo.setIsExpired((byte) 3);
                    } else {
                        vo.setIsExpired((byte) 2);
                    }
                } else {
                    if (rule.getStartDate() != null) {
                        if (rule.getStartDate().isAfter(LocalDate.now())) {
                            vo.setIsExpired((byte) 2);
                        } else {
                            vo.setIsExpired((byte) 3);
                        }
                    } else {
                        vo.setIsExpired((byte) 3);
                    }
                }
                BeanUtils.copyProperties(rule, vo);

                if (rule.getAddAdminId() != null) {
                    LitemallAdmin adminUser = adminService.findById(rule.getAddAdminId());
                    if (adminUser != null) {
                        vo.setAddAdminName(adminUser.getUsername());
                    }
                }

                if (isExpired != null) {
                    if (vo.getIsExpired() == isExpired) {
                        finalVos.add(vo);
                    }
                } else {
                    finalVos.add(vo);
                }
            });
        }
        return ResponseUtil.okList(vos);
    }

    /**
     * 添加
     *
     * @param dto     dto
     * @param adminId 管理员id
     * @return {@link Object}
     */
    public Object add(AdminRewardDto dto, Integer adminId) {
        LitemallRewardRule rule = new LitemallRewardRule();
        BeanUtils.copyProperties(dto, rule);
        DateTimeFormatter timeDtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate startTimes = LocalDate.parse(dto.getStartDate(), timeDtf);
        rule.setStartDate(startTimes);

        LocalDate endTimes = LocalDate.parse(dto.getEndDate(), timeDtf);
        rule.setEndDate(endTimes);
        rule.setAddTime(LocalDateTime.now());
        rule.setUpdateTime(LocalDateTime.now());
        rule.setDeleted(false);
        rule.setGiftCondition((byte) 1);
        rule.setStatus((byte) 1);
//    rule.setStatus();
        if (adminId != null) {
            rule.setAddAdminId(adminId);
        }

        litemallRewardRuleService.add(rule);

        //奖励规则配置
        List<AdminRewardConfigDto> adminRewardConfigDtos = dto.getAdminRewardConfigDtos();
        adminRewardConfigDtos.stream().forEach(config -> {
            LitemallRewardRuleConfig ruleConfig = new LitemallRewardRuleConfig();
            BeanUtils.copyProperties(config, ruleConfig);

            if (config.getPresentCouponId() != null && config.getPresentCouponId().size() > 0) {
                List<LumiereCouponStrategy> coupons = config.getPresentCouponId();
                Long[] couponArray = new Long[coupons.size()];
                for (int i = 0; i < coupons.size(); i++) {
                    couponArray[i] = coupons.get(i).getId();
                }

                ruleConfig.setPresentCouponId(couponArray);
            }
            ruleConfig.setPresentMethod(rule.getGiveMethod()==1?(byte)1:(byte)2);
            ruleConfig.setAddTime(LocalDateTime.now());
            ruleConfig.setUpdateTime(LocalDateTime.now());
            ruleConfig.setDeleted(false);
            ruleConfig.setRewardRuleId(rule.getId());
            ruleConfig.setDeleted(false);
            litemallRewardRuleConfigService.add(ruleConfig);
        });

        return ResponseUtil.ok("添加奖励规则成功");
    }

    /**
     * 更新
     *
     * @param dto dto
     * @return {@link Object}
     */
    public Object update(AdminRewardDto dto) {
        if (dto.getId() == null) {
            return ResponseUtil.fail(111, "规则id不能为空");
        }

        LitemallRewardRule rule = litemallRewardRuleService.findById(dto.getId());
        BeanUtils.copyProperties(dto, rule);

//    if(dto.getStatus() != null && dto.getStatus() == 1){
//      rule.setStatus((byte)3);
//    }

        //更改状态
        DateTimeFormatter timeDtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate startTimes = LocalDate.parse(dto.getStartDate(), timeDtf);
        rule.setStartDate(startTimes);

        LocalDate endTimes = LocalDate.parse(dto.getEndDate(), timeDtf);
        rule.setEndDate(endTimes);


        litemallRewardRuleService.update(rule);

        //奖励规则配置
        LitemallRewardRuleConfigExample example = new LitemallRewardRuleConfigExample();
        example.or().andRewardRuleIdEqualTo(dto.getId());
        List<LitemallRewardRuleConfig> configList = litemallRewardRuleConfigService.list(example);
        configList.stream().forEach(config -> {
            litemallRewardRuleConfigService.delete(config.getId());
        });

        //奖励规则配置
        List<AdminRewardConfigDto> adminRewardConfigDtos = dto.getAdminRewardConfigDtos();
        adminRewardConfigDtos.stream().forEach(config -> {
            LitemallRewardRuleConfig ruleConfig = new LitemallRewardRuleConfig();
            BeanUtils.copyProperties(config, ruleConfig);

            if (config.getPresentCouponId() != null && config.getPresentCouponId().size() > 0) {
                List<LumiereCouponStrategy> coupons = config.getPresentCouponId();
                Long[] couponArray = new Long[coupons.size()];
                for (int i = 0; i < coupons.size(); i++) {
                    couponArray[i] = coupons.get(i).getId() ;
                }

                ruleConfig.setPresentCouponId(couponArray);
            }

            ruleConfig.setAddTime(LocalDateTime.now());
            ruleConfig.setUpdateTime(LocalDateTime.now());
            ruleConfig.setRewardRuleId(rule.getId());
            ruleConfig.setDeleted(false);
            litemallRewardRuleConfigService.add(ruleConfig);
        });

        return ResponseUtil.ok("更改奖励规则成功");
    }

    /**
     * 删除
     *
     * @param ruleId 规则id
     * @return {@link Object}
     */
    public Object delete(Integer ruleId) {
        litemallRewardRuleService.delete(ruleId);
        return ResponseUtil.ok("删除成功");
    }

    /**
     * 细节
     *
     * @param ruleId 规则id
     * @return {@link Object}
     */
    public Object detail(Integer ruleId) {
        AdminRewardDto dto = new AdminRewardDto();
        LitemallRewardRule rule = litemallRewardRuleService.findById(ruleId);
        BeanUtils.copyProperties(rule, dto);

        DateTimeFormatter timeDtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        dto.setStartDate(rule.getStartDate().format(timeDtf));
        dto.setEndDate(rule.getEndDate().format(timeDtf));
        //规则配置
        List<LitemallRewardRuleConfig> configList = litemallRewardRuleConfigService.listByRuleId(ruleId);
        List<AdminRewardConfigDto> configDtos = configList.stream().map(config -> {
            AdminRewardConfigDto configDto = new AdminRewardConfigDto();
            BeanUtils.copyProperties(config, configDto);

            Long[] couponArray = config.getPresentCouponId();
            List<LumiereCouponStrategy> coupons = new ArrayList<>();
            String couponName = "";
            if(couponArray != null && couponArray.length > 0){
                for (int i = 0; i < couponArray.length; i++) {
                    LumiereCouponStrategy couponStrategy = lumiereCouponStrategyService.findByid(couponArray[i].longValue());
                    LumiereCoupon lumiereCoupon = lumiereCouponService.getById(couponStrategy.getCouponId());
                    couponStrategy.setCouponName(lumiereCoupon.getName());
                    couponName += lumiereCoupon.getName();
                    coupons.add(couponStrategy);
                }
            }

            configDto.setPresentCouponId(coupons);
            configDto.setCouponName(couponName);

            return configDto;
        }).collect(Collectors.toList());
        dto.setAdminRewardConfigDtos(configDtos);
        return ResponseUtil.ok(dto);
    }


    /**
     * 更新状态
     *
     * @param ruleId 规则id
     * @return {@link Object}
     */
    public Object updateStatus(Integer ruleId) {
        LitemallRewardRule rule = litemallRewardRuleService.findById(ruleId);

        if (rule.getStatus() == 1 || rule.getStatus() == 3) {
            rule.setStatus((byte) 2);
        } else if (rule.getStatus() == 2) {
            rule.setStatus((byte) 3);
        }

        litemallRewardRuleService.update(rule);

        return ResponseUtil.ok("修改状态成功");
    }

    /**
     * 日志
     *
     * @param registeDate registe日期
     * @param userName    用户名
     * @param email       电子邮件
     * @param page        页面
     * @param limit       限制
     * @return {@link Object}
     */
    public Object log(String registeDate, String userName, String email,Integer page,Integer limit) {
//      LitemallDistributionLogExample example = new LitemallDistributionLogExample();
        LocalDate registeD = null;
        if (registeDate != null) {
            DateTimeFormatter timeDtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            registeD = LocalDate.parse(registeDate, timeDtf);
        }
        if(page != null && limit != null){
            //PageHelper.startPage(page, limit);
        }

        if (userName == "") {
            userName = null;
        }

        if (email == "") {
            email = null;
        }

        List<LitemallDistributionLog> logs = distributionLogService.findByCondition(registeD,userName,email);
        List<AdminRewardLogVo> vos = new ArrayList<>();
        logs.stream().forEach(log -> {
            List<LitemallDistributionDetail> rewardDetailList =  litemallDistributionDetailService.countByLogId(log.getId());
            AdminRewardLogVo vo = new AdminRewardLogVo();
            if (log.getUserId() != null) {
                LitemallUser user = userService.findById(log.getUserId());

               if(user != null){
                   vo.setEmail(user.getEmail());
                   vo.setUserName(user.getUsername());
               }
            }
            vo.setId(log.getId());
            vo.setType(log.getType());
            vo.setInviteNum(log.getInviteNum());
            DateTimeFormatter timeDtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            vo.setRegisteDate(log.getInviteDate().format(timeDtf));
            Integer rewardNum = 0;
            if(rewardDetailList.size() > 0){
                for (int i = 0; i < rewardDetailList.size(); i++) {
                    rewardNum += rewardDetailList.get(i).getPresentCouponId().length;

                    if(rewardDetailList.get(i).getPresentPoints() != null && rewardDetailList.get(i).getPresentPoints().compareTo(new BigDecimal(0)) >0){
                        rewardNum ++;
                    }
                }
            }
            vo.setRewardNum(rewardNum);
                vos.add(vo);

        });
        return ResponseUtil.okList(vos,logs);
    }

    /**
     * 详细日志
     *
     * @param logId 日志id
     * @return {@link Object}
     */
    public Object detailByLog(Integer logId) {
        List<LitemallDistributionDetail> details = litemallDistributionDetailService.listByLogId(logId);

        List<AdminRewardDetailVo> vos = details.stream().map(detail -> {
            AdminRewardDetailVo vo = new AdminRewardDetailVo();
            //注册人账号
            vo.setRegisterName(detail.getRegisterId() != null&&detail.getRegisterId() !=0?userService.findById(detail.getRegisterId()).getUsername():detail.getRegisterUsername());
            StringBuffer couponName = new StringBuffer();

            Arrays.stream(detail.getPresentCouponId()).distinct().forEach(couponId -> {
                LumiereCouponStrategy couponStrategy = lumiereCouponStrategyService.findByid(couponId);
                LumiereCoupon coupon = lumiereCouponService.getById(couponStrategy.getCouponId());
                couponName.append(coupon.getName() + " ");
            });
            vo.setCouponName(couponName.toString());
            vo.setPoints(detail.getPresentPoints());
            return vo;
        }).collect(Collectors.toList());

        return ResponseUtil.okList(vos);
    }

    /**
     * 奖励统计
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return {@link Object}
     */
    public Object rewardStatistic(String startDate, String endDate) {
        LocalDate startD = null;
        LocalDate endD = null;

        DateTimeFormatter timeDtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");


        startD = LocalDate.parse(startDate, timeDtf);
        endD = LocalDate.parse(endDate, timeDtf);

        AdminRewardStatisticVo vo = new AdminRewardStatisticVo();

        //规则条数
        List<LitemallRewardRule> rules = litemallRewardRuleService.findByDate(startD, endD);

        List<LitemallRewardRule> rs = new ArrayList<>();
        //开始时间
        for (int i = 0; i < rules.size(); i++) {
            if(rules.get(i).getStartDate() != null && rules.get(i).getStartDate().isBefore(endD)){
                if((rules.get(i).getEndDate() != null && rules.get(i).getEndDate().plusDays(1).isAfter(endD) || rules.get(i).getEndDate() == null)){
                    rs.add(rules.get(i));
                    continue;
                }
            }

            if(rules.get(i).getEndDate() != null && rules.get(i).getEndDate().isBefore(startD)){
                if((rules.get(i).getStartDate() != null && rules.get(i).getStartDate().minusDays(1).isBefore(startD) || rules.get(i).getStartDate() == null)){
                    rs.add(rules.get(i));

                }
            }
        }


        List<LitemallDistributionLog> logs = litemallDistributionLogService.findByStartAndEnd(startD, endD);

        //获得用户
        Integer userNum = logs.stream().mapToInt(distributionLog -> distributionLog.getInviteNum()).sum();

        //优惠券数量
        Integer couponNum = 0;
        Double points = 0.00;

        for (int i = 0; i < logs.size(); i++) {
            List<LitemallDistributionDetail> details = litemallDistributionDetailService.listByLogId(logs.get(i).getId());
            couponNum += details.stream().mapToInt(detail -> detail.getPresentCouponId().length).sum();

            points = points + details.stream().mapToDouble(detail -> {
                if(detail.getPresentPoints() != null){
                    return detail.getPresentPoints().doubleValue();
                }

                return BigDecimal.ZERO.doubleValue();
            }).sum();
        }
        vo.setRuleNum(rs.size());
        vo.setDistributeNum(userNum);
        vo.setPoints(points);
        vo.setCouponNum(couponNum);
        return ResponseUtil.ok(vo);
    }

    /**
     * 分布统计
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return {@link Object}
     */
    public Object distributionStatistic(String startDate, String endDate) {
        DateTimeFormatter timeDtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate startD = LocalDate.parse(startDate, timeDtf);
        LocalDate endD = LocalDate.parse(endDate, timeDtf);

        long days =  endD.toEpochDay() - startD.toEpochDay();
        List<LocalDate> dates = new ArrayList<>();
        dates.add(startD);
        for (long i = 0; i < days; i++) {
            startD = startD.plusDays(1);
            dates.add(startD);
        }

        List<Integer> inviteNums = new ArrayList<>();
        dates.stream().forEach( date -> {
            List<LitemallDistributionLog> logs =   litemallDistributionLogService.findByDate(date);

            Integer inviteNum = 0;

            for (int i = 0; i < logs.size(); i++) {
                inviteNum += logs.get(i).getInviteNum();
            }
            inviteNums.add(inviteNum);
        });

        List<String> dateStr = new ArrayList<>();
        dates.stream().forEach(d -> {
            dateStr.add(d.toString());
        });

        LitemallDistributionVo vo = new LitemallDistributionVo();
        vo.setDateStr(dateStr);
        vo.setInviteNums(inviteNums);

        return ResponseUtil.ok(vo);
    }

    /**
     * 期统计
     *
     * @param ruleId 规则id
     * @param page   页面
     * @param limit  限制
     * @return {@link ResponseUtil.Response}
     */
    public ResponseUtil.Response periodStatistics(Integer ruleId , Integer page, Integer limit) {
        //获得当前规则 邀请人、数量 和 被邀请人、数量


        List<DistributionLogAndDetailVO> distributionLogAndDetailVoList = litemallDistributionLogService.selectJoinList(DistributionLogAndDetailVO.class,new MPJLambdaWrapper<LitemallDistributionLog>()
                .selectAll(LitemallDistributionLog.class)
                .select(LitemallDistributionDetail::getRegisterId,LitemallDistributionDetail::getPresentCouponId,LitemallDistributionDetail::getPresentPoints,LitemallDistributionDetail::getRegisterUsername)
                .rightJoin(LitemallDistributionDetail.class,LitemallDistributionDetail::getDisLogId,LitemallDistributionLog::getId)
                .eq(LitemallDistributionLog::getRuleId,ruleId)
        );
        PeriodStatisticsVO periodStatisticsVo = PeriodStatisticsVO.builder().build();
        //送出的优惠券数量
        Integer counpNum = 0;
        //邀请人数
        Integer invitationNum = 0;
        //被邀请人数
        Integer beInvited = 0;
        for (DistributionLogAndDetailVO distributionLogAndDetailVo : distributionLogAndDetailVoList) {
            counpNum+=distributionLogAndDetailVo.getPresentCouponId().length;
            invitationNum+=distributionLogAndDetailVo.getRegisterId()!=null?1:0;
            beInvited+=distributionLogAndDetailVo.getRegisterId()!=null?1:0;
        }
        periodStatisticsVo.setCounpNum(counpNum);
        periodStatisticsVo.setInvitationNum(invitationNum);
        periodStatisticsVo.setBeInvitedNum(beInvited);
        //组装数据表集
        List<DistributionLogAndDetailDTO> collect = distributionLogAndDetailVoList.stream().map(logAndDetailVo -> {
            DistributionLogAndDetailDTO distributionLogAndDetail = DistributionLogAndDetailDTO.builder().build();
            LitemallUser invitationUser = userService.findById(logAndDetailVo.getUserId());
            distributionLogAndDetail.setInvitationAccount(ObjectUtil.isNotNull(invitationUser) ? invitationUser.getUsername() : "UserID: "+logAndDetailVo.getUserId()+" logged out");
            distributionLogAndDetail.setInvitationNikeName(ObjectUtil.isNotNull(invitationUser) ? invitationUser.getNickname() : "UserID: "+logAndDetailVo.getUserId()+" logged out");
            distributionLogAndDetail.setInvitationDate(logAndDetailVo.getInviteDate());
            distributionLogAndDetail.setPresentPoints(logAndDetailVo.getPresentPoints());

            List<LumiereCouponStrategy> couponStrategies = lumiereCouponStrategyService.list(Wrappers.lambdaQuery(LumiereCouponStrategy.class)
                    .select(LumiereCouponStrategy::getCouponId, LumiereCouponStrategy::getName)
                    .in(LumiereCouponStrategy::getId, logAndDetailVo.getPresentCouponId())
            );
            distributionLogAndDetail.setCounpCode(couponStrategies.stream().map(couponStrategy->couponStrategy.getCouponId()).collect(Collectors.toList()).toString());
            distributionLogAndDetail.setCounpName(couponStrategies.stream().map(couponStrategy->couponStrategy.getName()).collect(Collectors.toList()).toString());

            LitemallUser beInvitationUser = userService.findById(logAndDetailVo.getRegisterId());
            distributionLogAndDetail.setBeInvitedAccount(ObjectUtil.isNotNull(beInvitationUser) ? beInvitationUser.getUsername() : logAndDetailVo.getRegisterUsername());
            distributionLogAndDetail.setBeInvitedNikeName(ObjectUtil.isNotNull(beInvitationUser) ? beInvitationUser.getNickname() : logAndDetailVo.getRegisterUsername());
            distributionLogAndDetail.setRegisterDate(logAndDetailVo.getAddTime());
            return distributionLogAndDetail;
        }).collect(Collectors.toList());
        Pageable pageable = new PageRequest(page - 1, limit);
        PageImpl<DistributionLogAndDetailDTO> list = PageUtil.getPageLumierePayMemberUserLogVo(pageable,collect);
        periodStatisticsVo.setPeriodStatisticsList(list);
        return ResponseUtil.ok(periodStatisticsVo);
    }
}
